
//
//Copyright (C) Sasha Goldshtein, 2009
//

#pragma once

#include <windows.h>

//
//This header file contains the declarations for various extensions that wrap
//the native OS support for more than 64 logical processors.
//For an overview of the new APIs that support more than 64 logical processors,
//consult the following document:
//	http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx
//

namespace MultiProcessorExtensions {

	public value class ProcessorNumber
	{
	public:
		ProcessorNumber(System::UInt16 group, System::Byte processor);

		property System::UInt16 Group { System::UInt16 get(); }
		property System::Byte Processor { System::Byte get(); }
	
	private:
		System::UInt16 _groupNumber;
		System::Byte _processorNumber;
	};
	
	public value class GroupAffinity
	{
	public:
		GroupAffinity(System::UIntPtr mask, System::UInt16 group);

		void Set(System::Byte processorNumber);
		void Clear(System::Byte processorNumber);
		void ClearAll();

		property System::UIntPtr Mask;
		property System::UInt16 Group;
	private:
		property System::UInt16 Reserved;
	};

	public value class ProcessorGroup
	{
	public:
		ProcessorGroup(System::UInt16 group, System::Byte processors);

		property System::UInt16 Group { System::UInt16 get(); }
		property System::Byte Processors { System::Byte get(); }
	
	private:
		System::UInt16 _groupNumber;
		System::Byte _processorCount;
	};

	public value class ProcessorRelationship
	{
	public:
		ProcessorRelationship(
			bool coreHasMultipleLogicalProcessors,
			System::Collections::Generic::IEnumerable<GroupAffinity>^ groupMask);

		property bool CoreHasMultipleLogicalProcessors { bool get(); }
		property System::Collections::Generic::IEnumerable<GroupAffinity>^ GroupMask {
			System::Collections::Generic::IEnumerable<GroupAffinity>^ get();
		}
	private:
		bool _coreHasMultipleLogicalProcessors;
		System::Collections::Generic::List<GroupAffinity>^ _groupMask;
	};

	public value class NumaNodeRelationship
	{
	public:
		NumaNodeRelationship(
			System::UInt32 nodeNumber,
			GroupAffinity groupAffinity);

		property System::UInt32 NodeNumber { System::UInt32 get(); }
		property GroupAffinity Affinity { GroupAffinity get(); }

	private:
		System::UInt32 _nodeNumber;
		GroupAffinity _groupAffinity;
	};

	public enum class ProcessorCacheType 
	{
		Unified,
		Instruction,
		Data,
		Trace
	};

	public value class CacheRelationship
	{
	public:
		CacheRelationship(
			System::Byte level,
			System::Byte associativity,
			System::UInt16 lineSize,
			System::UInt32 cacheSize,
			ProcessorCacheType type,
			GroupAffinity groupAffinity);

		property System::Byte Level { System::Byte get(); }
		property System::Byte Associativity { System::Byte get(); }
		property bool IsFullyAssociative { bool get(); }
		property System::UInt16 LineSize { System::UInt16 get(); }
		property System::UInt32 CacheSize { System::UInt32 get(); }
		property ProcessorCacheType Type { ProcessorCacheType get(); }
		property GroupAffinity Affinity { GroupAffinity get(); }

	private:
		System::Byte _level;
		System::Byte _associativity;
		System::UInt16 _lineSize;
		System::UInt32 _cacheSize;
		ProcessorCacheType _type;
		GroupAffinity _groupAffinity;
	};

	public value class ProcessorGroupInfo
	{
	public:
		ProcessorGroupInfo(
			System::Byte maxProcessorCount,
			System::Byte activeProcessorCount,
			System::UIntPtr activeProcessors);

		property System::Byte MaximumProcessorCount { System::Byte get(); }
		property System::Byte ActiveProcessorCount { System::Byte get(); }
		property System::UIntPtr ActiveProcessors { System::UIntPtr get(); }

		bool IsProcessorActive(System::Byte index);

	private:
		System::Byte _maxProcessorCount;
		System::Byte _activeProcessorCount;
		System::UIntPtr _activeProcessors;
	};

	public value class ProcessorGroupRelationship
	{
	public:
		ProcessorGroupRelationship(
			System::UInt16 maxGroupCount,
			System::UInt16 activeGroupCount,
			System::Collections::Generic::IEnumerable<ProcessorGroupInfo>^ processors);

		property System::UInt16 MaximumGroupCount { System::UInt16 get(); }
		property System::UInt16 ActiveGroupCount { System::UInt16 get(); }
		property System::Collections::Generic::IEnumerable<ProcessorGroupInfo>^ Processors {
			System::Collections::Generic::IEnumerable<ProcessorGroupInfo>^ get();
		}

	private:
		System::UInt16 _maxGroupCount;
		System::UInt16 _activeGroupCount;
		System::Collections::Generic::List<ProcessorGroupInfo>^ _processors;
	};

	public ref class Processor abstract sealed
	{
	public:
		static property System::UInt32 ActiveProcessorTotalCount { System::UInt32 get(); }
		static property System::UInt16 ActiveProcessorGroupCount { System::UInt16 get(); }
		static System::UInt32 GetActiveProcessorCount(System::UInt16 groupNumber);
		static property System::UInt16 MaximumProcessorGroupCount { System::UInt16 get(); }
		static System::UInt32 GetMaximumProcessorCount(System::UInt16 groupNumber);

		static property System::Collections::Generic::IEnumerable<ProcessorGroup>^ ProcessorGroups {
			System::Collections::Generic::IEnumerable<ProcessorGroup>^ get();
		}

		static property ProcessorNumber CurrentProcessor { ProcessorNumber get(); }

		static array<ProcessorRelationship>^ GetProcessorRelationships();
		static array<ProcessorGroupRelationship>^ GetProcessorGroupRelationships();
		static array<NumaNodeRelationship>^ GetNumaNodeRelationships();
		static array<CacheRelationship>^ GetCacheRelationships();
	};

	public ref class Numa abstract sealed
	{
	public:
		static System::UInt64 GetAvailableMemory(System::UInt16 numaNode);
		static GroupAffinity GetProcessorMask(System::UInt16 numaNode);
		static System::UInt16 GetProcessorNode(ProcessorNumber processor);
		static System::UInt16 GetProximityNode(System::UInt32 proximityId);
	};

	public ref class Process abstract sealed
	{
	public:
		static System::Diagnostics::Process^ CreateWithParentAffinity(
			System::String^ fileName,
			System::String^ arguments);
		static array<System::UInt16>^ GetProcessGroupAffinity(
			System::Diagnostics::Process^ process);
		static array<System::UInt16>^ GetProcessGroupAffinity(
			System::UInt32 processId);
		static array<System::UInt16>^ GetProcessGroupAffinity(
			System::IntPtr process);
	};

	public ref class Thread abstract sealed
	{
	public:
		static void SetThreadGroupAffinity(
			System::Diagnostics::ProcessThread^ thread,
			GroupAffinity affinity);
		static void SetThreadGroupAffinity(
			System::UInt32 threadId,
			GroupAffinity affinity);
		static void SetThreadGroupAffinity(
			System::IntPtr thread,
			GroupAffinity affinity);

		static GroupAffinity GetThreadGroupAffinity(
			System::Diagnostics::ProcessThread^ thread);
		static GroupAffinity GetThreadGroupAffinity(
			System::UInt32 threadId);
		static GroupAffinity GetThreadGroupAffinity(
			System::IntPtr thread);

		static property System::UInt32 CurrentThreadId { System::UInt32 get(); }
	};
}
